/*
 * @Author: 王炜皓
 * @Date: 2023-05-23 16:17:57
 * @LastEditTime: 2023-06-15 14:09:38
 * @LastEditors: 王炜皓
 * @Description: 通用方法
 * @FilePath: \cesium-tool\src\views\test\extend\plotCommon.ts
 */
import xp from '../extend/xp/algorithm';

const Cesium = window.Cesium;
/**
 * 创建随机（唯一）ID
 * @param num
 * @returns
 */
const newSessionid = (num?: number) => {
  let len = num || 32;
  let chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  let maxPos = chars.length;
  let pwd = "";
  for (let i = 0; i < len; i++) {
    pwd += chars.charAt(Math.floor(Math.random() * maxPos));
  }
  return pwd;
};
/**
 * 获取屏幕点的笛卡尔坐标
 * @param viewer 三维场景viewer
 * @param px 屏幕像素点
 * @returns {Object} Cartesian3 | false | null
 */
const getCatesian3FromPX = (viewer: any, px: { x: number; y: number }) => {
  let picks = viewer.scene.drillPick(px);
  let cartesian = null;
  let isOn3dtiles = false,
    isOnTerrain = false;
  // drillPick
  for (let i in picks) {
    let pick = picks[i];
    if (
      (pick && pick.primitive instanceof Cesium.Cesium3DTileFeature) ||
      (pick && pick.primitive instanceof Cesium.Cesium3DTileset) ||
      (pick && pick.primitive instanceof Cesium.Model)
    ) {
      //模型上拾取
      isOn3dtiles = true;
    }
    // 3dtilset
    if (isOn3dtiles) {
      viewer.scene.pick(px);
      cartesian = viewer.scene.pickPosition(px);
      if (cartesian) {
        let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
        if (cartographic.height < 0) cartographic.height = 0;
        let x = Cesium.Math.toDegrees(cartographic.longitude),
          y = Cesium.Math.toDegrees(cartographic.latitude),
          z = cartographic.height;
        cartesian = transformWGS84ToCartesian({ x, y, z });
      }
    }
  }
  // 地形
  let boolTerrain =
    viewer.terrainProvider instanceof Cesium.EllipsoidTerrainProvider;
  // Terrain
  if (!isOn3dtiles && !boolTerrain) {
    let ray = viewer.scene.camera.getPickRay(px);
    if (!ray) return null;
    cartesian = viewer.scene.globe.pick(ray, viewer.scene);
    isOnTerrain = true;
  }
  // 地球
  if (!isOn3dtiles && !isOnTerrain && boolTerrain) {
    cartesian = viewer.scene.camera.pickEllipsoid(
      px,
      viewer.scene.globe.ellipsoid
    );
  }
  if (cartesian) {
    let position = transformCartesianToWGS84(cartesian);
    if (position.z < 0) {
      position.z = 0.1;
      cartesian = transformWGS84ToCartesian(position);
    }
    return cartesian;
  }
  return false;
};
/**
 * 笛卡尔坐标转经纬度
 * @param cartesian Cartesian3
 * @returns {Object} { x, y, z }
 */
const transformCartesianToWGS84 = (cartesian: any) => {
  let ellipsoid = Cesium.Ellipsoid.WGS84;
  let cartographic = ellipsoid.cartesianToCartographic(cartesian);
  const x: number = Cesium.Math.toDegrees(cartographic.longitude);
  const y: number = Cesium.Math.toDegrees(cartographic.latitude);
  const z: number = cartographic.height;
  return { x, y, z };
};
/**
 * 经纬度转笛卡尔坐标
 * @param position - { x, y, z }
 * @returns {Object} Cartesian3
 */
const transformWGS84ToCartesian = (position: {
  x: number;
  y: number;
  z?: number;
}) => {
  position.z = position.z || 0;
  return position
    ? Cesium.Cartesian3.fromDegrees(
        position.x,
        position.y,
        position.z,
        Cesium.Ellipsoid.WGS84
      )
    : Cesium.Cartesian3.ZERO;
};
/**
 * 锁定视图
 * @param viewer - 三维场景
 * @param bool - 是否锁定
 */
const lockingMap = (viewer, bool) => {
  // 如果为真，则允许用户旋转相机。如果为假，相机将锁定到当前标题。此标志仅适用于2D和3D。
  viewer.scene.screenSpaceCameraController.enableRotate = bool;
  // 如果为true，则允许用户平移地图。如果为假，相机将保持锁定在当前位置。此标志仅适用于2D和Columbus视图模式。
  viewer.scene.screenSpaceCameraController.enableTranslate = bool;
  // 如果为真，允许用户放大和缩小。如果为假，相机将锁定到距离椭圆体的当前距离
  viewer.scene.screenSpaceCameraController.enableZoom = bool;
  // 如果为真，则允许用户倾斜相机。如果为假，相机将锁定到当前标题。这个标志只适用于3D和哥伦布视图。
  viewer.scene.screenSpaceCameraController.enableTilt = bool;
};
/**
 * 创建贝塞尔点集
 * @param anchorpoints
 * @returns
 */
const createBezierPoints = (anchorpoints: any[]) => {
  let degrees: any = [];
  for (let index = 0; index < anchorpoints.length; index++) {
    const degree = transformCartesianToWGS84(anchorpoints[index]);
    degrees.push(degree);
  }
  let numpoints = 100;
  let points: any = [];
  for (let i = 0; i <= numpoints; i++) {
    let point = computeBezierPoints(degrees, i / numpoints);
    const cartesian = transformWGS84ToCartesian(point);
    points.push(cartesian);
  }
  return points;
};
/**
 * 创建正多边形节点
 * @param centerPoint
 * @param endCartesian
 * @param num
 * @returns
 */
const getRegularPoints = (centerPoint, endCartesian, num) => {
  const centerP = transformCartesianToWGS84(centerPoint);
  let distance = 1;
  if (endCartesian) {
    const endDegree = transformCartesianToWGS84(endCartesian);
    distance = Cesium.Cartesian3.distance(
      new Cesium.Cartesian3.fromDegrees(centerP.x, centerP.y, 0),
      new Cesium.Cartesian3.fromDegrees(endDegree.x, endDegree.y, 0)
    );
  }
  let ellipse = new Cesium.EllipseOutlineGeometry({
    center: centerPoint,
    semiMajorAxis: distance,
    semiMinorAxis: distance,
    granularity: 0.0001, //0~1 圆的弧度角,该值非常重要,默认值0.02,如果绘制性能下降，适当调高该值可以提高性能
  });
  let geometry = new Cesium.EllipseOutlineGeometry.createGeometry(ellipse);
  let circlePoints: any = [];
  let values = geometry.attributes.position.values;
  if (!values) return;
  let posNum = values.length / 3; //数组中以笛卡尔坐标进行存储(每3个值一个坐标)
  for (let i = 0; i < posNum; i++) {
    let curPos = new Cesium.Cartesian3(
      values[i * 3],
      values[i * 3 + 1],
      values[i * 3 + 2]
    );
    circlePoints.push(curPos);
  }
  let resultPoints: any = [];
  let pointsapart = Math.floor(circlePoints.length / num);
  for (let j = 0; j < num; j++) {
    resultPoints.push(circlePoints[j * pointsapart]);
  }
  return resultPoints;
};
/**
 * 计算贝塞尔曲线特征点
 * @param anchorpoints
 * @param t
 * @returns -  {{x: number, y: number}}
 * @private
 */
const computeBezierPoints = (anchorpoints: any[], t: number) => {
  let x = 0,
    y = 0;
  let Binomial_coefficient = computeBinomial(anchorpoints);
  for (let j = 0; j < anchorpoints.length; j++) {
    let tempPoint = anchorpoints[j];
    const coefficient =
      Math.pow(1 - t, anchorpoints.length - 1 - j) *
      Math.pow(t, j) *
      Binomial_coefficient[j];
    x += tempPoint.x * coefficient;
    y += tempPoint.y * coefficient;
  }
  return { x, y };
};
/**
 * 计算二项式系数
 * @param anchorpoints
 * @returns - {Array}
 * @private
 */
const computeBinomial = (anchorpoints: any[]) => {
  let lens = anchorpoints.length;
  let Binomial_coefficient: number[] = [];
  Binomial_coefficient.push(1);
  for (let k = 1; k < lens - 1; k++) {
    let cs = 1,
      bcs = 1;
    for (let m = 0; m < k; m++) {
      cs = cs * (lens - 1 - m);
      bcs = bcs * (k - m);
    }
    Binomial_coefficient.push(cs / bcs);
  }
  Binomial_coefficient.push(1);
  return Binomial_coefficient;
};
const hexToCesiumColor=(hex, alpha)=>{
  if(hex){
    hex = hex.replace("#", "");

    // 提取红色、绿色和蓝色分量
    var red = parseInt(hex.substring(0, 2), 16) / 255;
    var green = parseInt(hex.substring(2, 4), 16) / 255;
    var blue = parseInt(hex.substring(4, 6), 16) / 255;
  
    // 创建并返回 Cesium.Color 对象
    return new Cesium.Color(red, green, blue, alpha);
  }else{
    return Cesium.Color.RED.withAlpha(0.5)
  }
  // 去除可能存在的 # 符号
 
}
const createRemindertip=(arr: any, position: any, show: boolean)=>{
  let tooltip = document.getElementById("toolTip");
  let style: any, _x: number, _y: number;
  let _color: string = "";
  if (arr && typeof arr === "object") {
    style = arr;
  }
  if (style && style.origin) {
    style.origin === "center" && ((_x = 15), (_y = -12));
    style.origin === "top" && ((_x = 15), (_y = -44));
    style.origin === "bottom" && ((_x = 15), (_y = 20));
  } else {
    (_x = 15), (_y = 20);
  }
  if (style && style.color) {
    style.color === "white" &&
      (_color = "background: rgba(255, 255, 255, 0.8);color: black;");
    style.color === "black" &&
      (_color = "background: rgba(0, 0, 0, 0.8);color: white;");
    style.color === "yellow" &&
      (_color =
        "color: black;background-color: #ffcc33;border: 1px solid white;");
  } else {
    _color = "background: rgba(0, 0, 0, 0.8);color: white;";
  }
  if (tooltip === null) {
    const viewerDom = document.getElementsByClassName("cesium-viewer")[0];
    let elementbottom = document.createElement("div");
    viewerDom.append(elementbottom);
    let html =
      '<div id="toolTip" style="display: none;pointer-events: none;position: absolute;z-index: 1000;opacity: 0.8;border-radius: 4px;padding: 4px 8px;white-space: nowrap;font-family:黑体;color:white;font-weight: bolder;font-size: 14px;' +
      _color +
      '"></div>';
    viewerDom.insertAdjacentHTML("beforeend", html);
    tooltip = document.getElementById("toolTip");
  }
  if (show) {
    tooltip!.innerHTML = arr;
    tooltip!.style.left = position.x + _x! + "px";
    tooltip!.style.top = position.y + _y! + "px";
    tooltip!.style.display = "block";
  } else {
    tooltip!.style.display = "none";
  }
  return {
    tooltip: tooltip,
    style: style,
    showAt: function (position: any, text: any) {
      this.tooltip!.innerHTML = text;
      if (this.style && this.style.origin) {
        this.style.origin === "center" &&
          ((_x = 15), (_y = -this.tooltip!.offsetHeight / 2));
        this.style.origin === "top" &&
          ((_x = 15), (_y = -this.tooltip!.offsetHeight - 20));
        this.style.origin === "bottom" && ((_x = 15), (_y = 20));
      } else {
        (_x = 15), (_y = -this.tooltip!.offsetHeight / 2);
      }
      this.tooltip!.style.left = position.x + _x + "px";
      this.tooltip!.style.top = position.y + _y + "px";
      this.tooltip!.style.display = "block";
    },
    show: function (show: boolean) {
      if (show) {
        this.tooltip!.style.display = "block";
      } else {
        this.tooltip!.style.display = "none";
      }
    },
  };
  
}
const getAttackArrowPoints = (positions: any[]) => {
  let lnglatArr: any[] = [];
  for (let i = 0; i < positions.length; i++) {
    let lnglat = transformCartesianToWGS84(positions[i]);
    lnglatArr.push([lnglat.x, lnglat.y]);
  }
  let res = xp.algorithm.tailedAttackArrow(lnglatArr);
  let index = JSON.stringify(res.polygonalPoint).indexOf('null');
  let points = [];
  if (index == -1) points = res.polygonalPoint;
  return points;
};
const destroyTip=()=> {
  let tooltip = document.getElementById("toolTip");
  if (tooltip) (tooltip as any).style.display = "none";

} /**
* 获取椭圆和圆形的轴长
* @param points
* @returns
*/

const getSemiAxis = (points: any[]) => {
  return points.length === 2
    ? Cesium.Cartesian3.distance(points[0], points[1])
    : 0;
};
 /**
   * 获取椭圆旋转的角度
   * @param points
   * @returns
   */
 const getEllipticAngle = (points: any[]) => {
  let p1 = transformCartesianToWGS84(points[0]);
  let p2 = transformCartesianToWGS84(points[1]);
  let angle = 450 - calculateAngle(p1, p2);
  return Cesium.Math.toRadians(angle);
};
/**
 * 计算两点对于正北方向的朝向角度 [0,360]
 * @param start format:{'x': 130, 'y': 20 }
 * @param end format:{'x': 130, 'y': 20 }
 * @returns
 */
const calculateAngle = (
  start: { x: number; y: number },
  end: { x: number; y: number }
) => {
  let rad = Math.PI / 180,
    lat1 = start.y * rad,
    lat2 = end.y * rad,
    lon1 = start.x * rad,
    lon2 = end.x * rad;
  const a = Math.sin(lon2 - lon1) * Math.cos(lat2);
  const b =
    Math.cos(lat1) * Math.sin(lat2) -
    Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1);
 
  return radiansToDegrees(Math.atan2(a, b));
};
function radiansToDegrees(radians: number) {
  const degrees = radians % (2 * Math.PI);
  return (degrees * 180) / Math.PI < 0
    ? 360 + (degrees * 180) / Math.PI
    : (degrees * 180) / Math.PI;
}

export {
  newSessionid,
  getCatesian3FromPX,
  lockingMap,
  transformCartesianToWGS84,
  transformWGS84ToCartesian,
  createBezierPoints,
  getRegularPoints,
  hexToCesiumColor,
  createRemindertip,
  getAttackArrowPoints,
  destroyTip,
  getSemiAxis,
  calculateAngle,
  getEllipticAngle,
  radiansToDegrees,
};